package lock

import (
	"gitee.com/zaper/redis-client/redis_options"
	"gitee.com/zaper/software-framework/util"
	"github.com/google/uuid"
	"time"
)

type DistributedLock struct {
	lockName string
	timeout  time.Duration
	uuid     string
}

func NewDistributedLock(lockName string, timeout time.Duration) *DistributedLock {
	return &DistributedLock{
		lockName: lockName,
		timeout:  timeout,
	}
}

func (lock *DistributedLock) AcquireLock() bool {
	var redisOptions *redis_options.RedisOptions
	util.Retry(func() bool {
		redisOptions = redis_options.NewRedisOptions()
		if redisOptions != nil {
			return true
		}
		return false
	}, 5)
	defer redisOptions.Close()
	end := time.Now().Add(lock.timeout)
	lock.uuid = uuid.New().String()
	for time.Now().Before(end) {
		rt, err := redisOptions.SetNx(lock.lockName, lock.uuid, lock.timeout)
		if err == nil {
			return rt
		}
	}
	return false
}

func (lock *DistributedLock) ReleaseLock() bool {
	redisOptions := redis_options.NewRedisOptions()
	defer redisOptions.Close()
	script := `
	if redis.call("get", KEYS[1]) == ARGV[1] then
    	return redis.call("del", KEYS[1])
	else
    	return 0
	end`
	rt := util.Retry(func() bool {
		_, err := redisOptions.Eval(script, []string{lock.lockName}, lock.uuid)
		if err != nil {
			return false
		}
		return true
	}, 5)
	return rt
}
